//
//  CCVSCustomLayout.m
//  CollectionViewTest
//
//  Created by Pasirstein, David B on 5/11/13.
//  Copyright (c) 2013 Pasirstein, David B. All rights reserved.
//

#import "CCVSCustomLayout.h"

@interface CCVSCustomLayout ()

@property (readonly,nonatomic) NSArray * ccvsColumns; //an array of columns
@property (strong,nonatomic) NSMutableDictionary * calulatedLayout;
@property (nonatomic) CGFloat prevWidth;
@property (nonatomic) CGFloat totalHeight;
@end

//if the column does not have a width defined AND CCVS_LAYOUT_FULL_SCALE
//then we want to pick a rational scale size.
//if there is one column then it will be about the width of the view
//but if there are multiple columns, then we should size in a way
//the lets the user know to scroll to the right... e.g. 80% = 0.80
#define DEFAULT_FULL_SCALE_PERCENT_OF_SUPERVIEW 0.40

@implementation CCVSCustomLayout

@synthesize vc = _vc;
@synthesize scaleType = _scaleType;
@synthesize superView = _superView;
@synthesize ccvsColumns = _ccvsColumns;
@synthesize calulatedLayout = _calulatedLayout;
@synthesize prevWidth = _prevWidth;
@synthesize totalHeight = _totalHeight;

-(NSMutableDictionary *)calulatedLayout
{
    if (!_calulatedLayout || self.prevWidth != self.superView.frame.size.width) {
        _calulatedLayout = [[NSMutableDictionary alloc] initWithCapacity:[self.ccvsColumns count]+1];
        self.prevWidth = self.superView.frame.size.width;
        //load layout here
        [self calculateLayoutMap];
        //
    }
    return _calulatedLayout;
}

//if things change on use
//such as anytype of collection view
//reload or change of orientation
-(void)invalidateLayout
{
    self.calulatedLayout = nil;
    self.totalHeight = 0;
    [super invalidateLayout];
}

-(id)init {
    self = [super init];
    //defaults
    self.minimumInteritemSpacing = CCVS_BOARDERSIZE;
    self.minimumLineSpacing = CCVS_BOARDERSIZE;
    self.scaleType = CCVS_LAYOUT_SCALE_TO_SUPERVIEW;
    return self;
}

-(NSArray *)ccvsColumns
{
    return self.vc.ccvsColumns;
}

+(CGFloat)getTotalWidth:(NSArray*)ccvsColumns inSuperView:(UIView*)superView fitToSuperView:(enum CCVS_LAYOUT_SCALE)fit
{
    CGFloat width;
    ///if it needs to fit, the do the quick calc and return.
    if (fit == CCVS_LAYOUT_SCALE_TO_SUPERVIEW) {
        width = superView.frame.size.width - (CCVS_BOARDERSIZE*2);
        ///
    } else {
        width = CCVS_BOARDERSIZE;
        CGFloat colWidth = 0;
        ////
        for (int i = 0; i < [ccvsColumns count]; i++) {
            //if a col width is not specified, then we assume it to be
            //approx the full view width
            colWidth = [CCVSCustomLayout getWidthOfColumn:i withData:ccvsColumns inSuperView:superView fitToSuperView:CCVS_LAYOUT_FULL_SCALE];
            width = width + colWidth + CCVS_BOARDERSIZE;
        }
    }
    return width;
}


+(CGFloat)getWidthOfColumn:(int)column withData:(NSArray*)ccvsColumns inSuperView:(UIView*)superview fitToSuperView:(enum CCVS_LAYOUT_SCALE)fit
{
    CGFloat displayWidth = ((CCVSColumn*)ccvsColumns[column]).width;
    CGFloat percentWidth = ((CCVSColumn*)ccvsColumns[column]).percentWidthOfSuperView;
    if (displayWidth < 1 && !percentWidth) {
        displayWidth = ([ccvsColumns count] == 1) ? superview.frame.size.width : (superview.frame.size.width * DEFAULT_FULL_SCALE_PERCENT_OF_SUPERVIEW);
        if (fit == CCVS_LAYOUT_FULL_SCALE) {
            //only for full scale here b/c if scaling, we will handle differently
            //ok but the Width should really be a little bit smaller for astetics
            //left and right boarder
            displayWidth -= CCVS_BOARDERSIZE * 2;
        }
    } else if (percentWidth) {
        displayWidth = superview.frame.size.width * percentWidth;
    }
    //if we need to scale...
    if (fit == CCVS_LAYOUT_SCALE_TO_SUPERVIEW) {
        //we need to scale
        CGFloat scale = [CCVSCustomLayout getTotalWidth:ccvsColumns inSuperView:superview fitToSuperView:CCVS_LAYOUT_SCALE_TO_SUPERVIEW];
        //  actual over total is proportional to resized over max
        displayWidth = (displayWidth * scale) / [CCVSCustomLayout getTotalWidth:ccvsColumns inSuperView:superview fitToSuperView:CCVS_LAYOUT_FULL_SCALE];

        //ok but the Width should really be a little bit smaller for astetics
        //left and right boarder
        displayWidth -= CCVS_BOARDERSIZE;
        
    }
    return displayWidth;
}

-(CGSize)collectionViewContentSize
{
    CGSize retVal = [super collectionViewContentSize];
    if ((self.scaleType == CCVS_LAYOUT_FULL_SCALE) && self.superView) {
        //for full scale, we need to adjust the height b/c
        //the flowlayout mis-calculates...it calculates there is only
        //one item per row.  that not what we want
        CGFloat height = retVal.height;
        if (self.totalHeight > 0) height = self.totalHeight;
        retVal = CGSizeMake([CCVSCustomLayout getTotalWidth:self.ccvsColumns inSuperView:self.superView fitToSuperView:CCVS_LAYOUT_FULL_SCALE], height );
    }
    if (self.totalHeight > 0) retVal.height = self.totalHeight;
    return retVal;
}

//generate the layout map
-(void)calculateLayoutMap
{
    CGPoint lastxy = CGPointMake(self.minimumInteritemSpacing, 0);
    CGSize size = CGSizeMake(0, 0);
    for (int item = 0; item < [self.ccvsColumns count]; item++) {
        NSMutableArray * rects = [[NSMutableArray alloc] init];
        NSMutableArray * sectionRects = [[NSMutableArray alloc] init];
        //for the first one, we also want the sections
        for (int section = 0; section < [[(CCVSColumn*)self.ccvsColumns[item] getSectionsFilterEmptySections:self.vc.filterEmptySections] count]; section++) {
            //if its the first column, then include the sections
            if (item == 0) {
                size = [self.vc  collectionView:self.collectionView layout:self referenceSizeForHeaderInSection:section];
                [sectionRects addObject:[NSValue valueWithCGRect:CGRectMake(0, lastxy.y, size.width, size.height)]];
                lastxy.y += size.height;
            } else {
                //its not the first column so lets use the section headers
                //that we already calculated...
                CGRect rect;
                [(NSValue*)[self.calulatedLayout valueForKey:@"SECTIONS"][section] getValue:&rect];
                lastxy.y += rect.size.height;
            }
            lastxy.y += self.minimumLineSpacing;
            NSIndexPath* iPath = [NSIndexPath indexPathForItem:item inSection:section];
            size = [self.vc collectionView:self.collectionView layout:self sizeForItemAtIndexPath:iPath];
            [rects addObject:[NSValue valueWithCGRect:CGRectMake(lastxy.x, lastxy.y, size.width, size.height)]];
            lastxy.y += size.height;
        }
        lastxy.y += self.minimumLineSpacing;
        if (self.totalHeight < lastxy.y) self.totalHeight = lastxy.y;
        lastxy.y = 0;
        lastxy.x += size.width + self.minimumInteritemSpacing;
        if (item==0) [self.calulatedLayout setObject:sectionRects forKey:@"SECTIONS"];
        [self.calulatedLayout setObject:rects forKey:[NSNumber numberWithInt:item].stringValue];
     }
}

-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSMutableArray * attribs = [[NSMutableArray alloc] init];
    CGRect rect2;
    NSArray * rects;
    NSArray * sectionRects;
    for (int item = 0; item < [self.ccvsColumns count]; item++){
        rects = [self.calulatedLayout valueForKey:[NSNumber numberWithInt:item].stringValue];
        if (item == 0) sectionRects = [self.calulatedLayout valueForKey:@"SECTIONS"];
        for (int section = 0; section < [[(CCVSColumn*)self.ccvsColumns[item] getSectionsFilterEmptySections:self.vc.filterEmptySections] count]; section++) {
            [(NSValue *)rects[section] getValue:&rect2];
            if (CGRectIntersectsRect(rect, rect2)) {
                //then we need to add the cell
                 NSIndexPath* iPath = [NSIndexPath indexPathForItem:item inSection:section];
                [attribs addObject:[self layoutAttributesForItemAtIndexPath:iPath]];
            }
            if (item == 0) {
                //now for the section headers
                [(NSValue *)sectionRects[section] getValue:&rect2];
                if (CGRectIntersectsRect(rect, rect2)) {
                    //then we need to add the section header
                    NSIndexPath* iPath = [NSIndexPath indexPathForItem:item inSection:section];
                    [attribs addObject:[self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:iPath]];
                }
            }
        } //end for section
    } //end for item
    return [attribs copy];
}

-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes * attrib = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    CGRect rect;
    NSArray * rects = [self.calulatedLayout valueForKey:[NSNumber numberWithInt:indexPath.item].stringValue];
    [(NSValue *)rects[indexPath.section] getValue:&rect];
    attrib.frame = rect;
    return attrib;
}

-(UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes * attrib = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:kind withIndexPath:indexPath];
    CGRect rect;
    if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
        NSArray * rects = [self.calulatedLayout valueForKey:@"SECTIONS"];
        [(NSValue *)rects[indexPath.section] getValue:&rect];
        attrib.frame = rect;
    } else {
        //footer or other?
    }
    return attrib;
}


@end
